<?php

require_once(fvSite::$fvConfig->get("path.entity") . "fvroot.class.php");

/**
 *
 */
abstract class fvRootManager {

    protected $rootObj = null;
    static $instace = null;

    const GET_EQUAL = '=';
    const GET_NOT_EQUAL = '<>';
    const GET_GT = '>';
    const GET_GTE = '>=';
    const GET_LT = '<';
    const GET_LTE = '<=';
    const GET_LIKE = 'LIKE';
    const GET_NOT_LIKE = 'NOT LIKE';

    const GET_CHECK_CASE = 'cc';
    const GET_UNCHECK_CASE = 'ucc';

    /**
     *
     */
    protected function __construct () {
    }

    abstract static function getInstance();

    public function getByPk ($pk) {

        $primaryKey = $this->rootObj->getPkName();
        $tableName = $this->rootObj->getTableName();

        $where = '';
        $params = array();
        if (is_array($primaryKey)) {
            if (!is_array($pk)) return false;

            foreach ($primaryKey as $key => $pkName) {
                $where .= (($where)?' AND ':'') . "$pkName = ?";
                if (array_key_exists($pkName, $pk)) {
                    $params[] = $pk[$pkName];
                } else {
                    if (!isset($pk[$key])) return false;
                    $params[] = $pk[$key];
                }
            }
        } else {
            $where = "$primaryKey = ?";
            $params = array($pk);
        }

        $data = fvSite::$DB->getRow("SELECT * FROM $tableName WHERE $where", $params);

        if (fvSite::$DB->lastSelectCount) {
            $o = clone $this->rootObj;
            $o->hydrate($data);

            return $o;
        }

        return false;
    }

    function getAll() {
        $args = func_get_args();

        $where = $order = $limit = "";
        $func_option = '*';
        $params = array();

        if (!empty($args[0])) $where = "WHERE (" . $args[0] . ")";
        if (!empty($args[1])) $order = "ORDER BY " . $args[1] . "";
        if (!empty($args[2])) $limit = explode(',', $args[2]);
        if (isset($args[3]))
        $params = (is_array(@$args[3]))?@$args[3]:array(@$args[3]);

        if (isset($args[4])) $func_option = 'distinct '.$args[4];
        $query = "SELECT $func_option FROM " . $this->rootObj->getTableName() . " $where $order";
        if (is_array($limit) && count($limit) == 2) {
            $res = fvSite::$DB->limitQuery($query, $limit[0], $limit[1], $params);
        }
        else {
            $res = fvSite::$DB->query($query, $params);
        }

        $result = array();

        if (!DB::isError($res)) {
            while ($row = $res->fetchRow()) {
                $o = clone $this->rootObj;
                $o->hydrate($row);

                $result[] = $o;
            }
        }

        return $result;
    }

    function htmlSelect ($field, $empty = "", $where = null, $order = null, $limit = null, $args = array()) {
        $objs = $this->getAll($where, $order, $limit, $args);

        $result = array();
        if (!empty($empty)) {
            $result[''] = $empty;
        }

        foreach ($objs as $obj) {
            $result[$obj->getPk()] = $obj->$field;
        }

        return $result;
    }

    public function getCount() {
        $args = func_get_args();

        $where = "";
        $params = array();

        if (!empty($args[0])) $where = "WHERE ({$args[0]})";
        if (!empty($args[1])) $params = (is_array($args[1]))?$args[1]:array($args[1]);
        $query = "SELECT count(*) as cnt FROM " . $this->rootObj->getTableName() . " $where";

        $count = fvSite::$DB->getOne($query, $params);

        if (fvSite::$DB->lastSelectCount) {
            return $count;
        }

        return false;
    }

    public function __call($name, $arguments) {
        if (strpos($name, 'getBy') === 0) {
            if (($fieldName = $this->checkName(substr($name, 5))) === false) {
                throw new EManagerError("Can't recognozed filed");
            }

            $condition = (!empty($arguments[1]))?$arguments[1]:self::GET_EQUAL;
            if (($cc = (!empty($arguments[2]))?($arguments[2] == self::GET_UNCHECK_CASE):true) === false) {
                $value = strtoupper($arguments[0]);
            } else {
                $value = $arguments[0];
            }

            if ($cc) {
                $where = "{$fieldName} {$condition} ?";
            } else {
                $where = "UPPER({$fieldName}) {$condition} ?";
            }

            return $this->getAll($where, null, null, array($value));
        } else {
            throw new EManagerError("Call to undefined function");
        }
    }

    protected function checkName($name) {
        if ($this->rootObj->hasField($name)) return $name;

        for ($i = 1; $i < strlen($name); $i++) {
            if ($name{$i} == strtoupper($name{$i})) {
                $name = substr($name, 0, $i) . "_" . strtolower($name{$i}) . substr($name, $i + 1);
                $i++;
            }
        }
        $name = strtolower($name);

        if ($this->rootObj->hasField($name)) return $name;
        return false;
    }

    public function massUpdate($where, $updateFields) {

        $o = clone $this->rootObj;
        
        foreach ($updateFields as $field => $value) {
            $o[$field] = $value;            
        }

        $insertList = array();
        foreach ($o->getFieldList() as $field) {
            if ($o->isChanged($field) || $o->autoValue($field, $saveType)) {
                if (in_array($o->getFieldType($field), fvRoot::getSerializedTypes())) {
                    $insertList[$field] = serialize($o->get($field));
                }
                else $insertList[$field] = $o->get($field);
            }
        }
        
        try {
            $dbResult = fvSite::$DB->autoExecute($o->getTableName(), $insertList, DB_AUTOQUERY_UPDATE, $where);
        } catch (Exception $e) {
            var_dump($e->getMessage());
        }
        
        if (DB::isError($dbResult)) {
            throw new EDatabaseError($dbResult->getMessage());
        }

        return true;
    }
}

?>
